package com.tongji.diy.view.component3D
{
	import com.tongji.diy.event.UploadRoomBorderEvent;
	import com.tongji.diy.model.RoomControlPointArc;
	import com.tongji.diy.utils.ArcBorderUtils;
	import com.tongji.diy.utils.RoomParameters;
	import com.tongji.diy.view.component3D.RoomBorder;
	import com.tongji.diy.view.material.DefaultMaterial;
	
	import de.polygonal.ds.DListNode;
	
	import flare.collisions.MouseCollision;
	import flare.core.Mesh3D;
	import flare.core.Surface3D;
	import flare.core.Texture3D;
	import flare.materials.Material3D;
	import flare.materials.Shader3D;
	import flare.materials.filters.TextureFilter;
	
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Shape;
	import flash.geom.Point;
	
	public class RoomBorderArc extends BaseRoomBorder
	{
		private var material:Material3D;
		
		private var startPoint:DListNode;
		private var ctrlPoint:DListNode;
		private var endPoint:DListNode;
		private const N:uint = ArcBorderUtils.N;
		private const STEP:Number = ArcBorderUtils.STEP;
		//1/0.05=20
		private var n:uint = uint(1.00/STEP);
		
		//points保存从start前一个点到end后一个点的数据
		private var _points:Vector.<Point> = new Vector.<Point>;
		
		public function RoomBorderArc(startPoint:DListNode,endPoint:DListNode,ctrlPoint:DListNode,material:Material3D)
		{
			super();
			
			var shader:Shader3D = material.clone() as Shader3D;
			if(shader.filters.length > 1)
				shader.filters.pop();
			this.material = shader as Material3D;
			
			this.startPoint = startPoint;
			this.ctrlPoint = ctrlPoint;
			this.endPoint = endPoint;
			
			this.ctrlPoint.data.parentArc = this;
			
			this.startPoint.data.nextBorder = this;
			this.endPoint.data.prevBorder = this;
			
			//points:n+1+2
			//borders:n
			for(n+=3;n>0;n--)
				_points.push(new Point());
			
			//refresh()
			//Bezier Curve
			var sP:Point = new Point(startPoint.data.x,startPoint.data.y);
			var cP:Point = new Point(ctrlPoint.data.x,ctrlPoint.data.y);
			var eP:Point = new Point(endPoint.data.x,endPoint.data.y);
			
			_points[0] = new Point(startPoint.prev.data.x,startPoint.prev.data.y);
			for(var i:uint = 0;i <= uint(1/this.STEP);i++)
			{
				//point at i
				var p:Point = new Point();
				p.x = sP.x*ArcBorderUtils.bez(N,0,i*STEP)+cP.x*ArcBorderUtils.bez(N,1,i*STEP)+eP.x*ArcBorderUtils.bez(N,2,i*STEP);
				p.y = sP.y*ArcBorderUtils.bez(N,0,i*STEP)+cP.y*ArcBorderUtils.bez(N,1,i*STEP)+eP.y*ArcBorderUtils.bez(N,2,i*STEP);
				_points[i+1] = p;
			}
			_points[_points.length-1] = new Point(endPoint.next.data.x,endPoint.next.data.y);
			
			/*
			*	画墙
			*/
			
			if(surfaces.length)
			{
				surfaces[0].dispose();
				surfaces[1].dispose();
				surfaces[2].dispose();
			}
			
			/*
			网格初始化
			*/
			
			//内墙
			surfaces[0] = new Surface3D();
			shader = this.material.clone() as Shader3D;
			if(shader.filters.length > 1)
				shader.filters.pop();
			surfaces[0].material = shader as Material3D;
			surfaces[0].addVertexData( Surface3D.POSITION );
			surfaces[0].addVertexData( Surface3D.UV0 );
			surfaces[0].addVertexData( Surface3D.NORMAL );
			//墙顶
			surfaces[1] = new Surface3D();
			surfaces[1].material = DefaultMaterial.getInst();
			surfaces[1].addVertexData( Surface3D.POSITION );
			surfaces[1].addVertexData( Surface3D.UV0 );
			surfaces[1].addVertexData( Surface3D.NORMAL );
			//外墙
			surfaces[2] = new Surface3D();
			surfaces[2].material = DefaultMaterial.getInst();
			surfaces[2].addVertexData( Surface3D.POSITION );
			surfaces[2].addVertexData( Surface3D.UV0 );
			surfaces[2].addVertexData( Surface3D.NORMAL );
			
			for(var j:uint = 0; j < _points.length-3; j++)
				this.drawBorder( _points[j], _points[j+1], _points[j+2],_points[j+3], j);
			
			//更新贴图大小
			//内墙
			shader = surfaces[0].material as Shader3D;
			var texFilter:TextureFilter = shader.filters[0] as TextureFilter;
			var point:Point = new Point(surfaces[0].vertexVector[0] - surfaces[0].vertexVector[16], surfaces[0].vertexVector[2] - surfaces[0].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			//墙顶
			shader = surfaces[1].material as Shader3D;
			texFilter = shader.filters[0] as TextureFilter;
			point = new Point(surfaces[1].vertexVector[0] - surfaces[1].vertexVector[16], surfaces[1].vertexVector[2] - surfaces[1].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			//外墙
			shader = surfaces[2].material as Shader3D;
			texFilter = shader.filters[0] as TextureFilter;
			point = new Point(surfaces[2].vertexVector[0] - surfaces[2].vertexVector[16], surfaces[2].vertexVector[2] - surfaces[2].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			surfaces[0].upload(this.scene);
			surfaces[1].upload(this.scene);
			surfaces[2].upload(this.scene);
		}
		
		override public function refresh(mouse:MouseCollision):void
		{
			mouse.removeCollisionWith(this);
			
			//ArcBorderUtils.bezier Curve
			var sP:Point = new Point(startPoint.data.x,startPoint.data.y);
			var cP:Point = new Point(ctrlPoint.data.x,ctrlPoint.data.y);
			var eP:Point = new Point(endPoint.data.x,endPoint.data.y);
			
			_points[0] = new Point(startPoint.prev.data.x,startPoint.prev.data.y);
			for(var i:uint = 0;i <= uint(1/this.STEP);i++)
			{
				//point at i
				var p:Point = new Point();
				p.x = sP.x*ArcBorderUtils.bez(N,0,i*STEP)+cP.x*ArcBorderUtils.bez(N,1,i*STEP)+eP.x*ArcBorderUtils.bez(N,2,i*STEP);
				p.y = sP.y*ArcBorderUtils.bez(N,0,i*STEP)+cP.y*ArcBorderUtils.bez(N,1,i*STEP)+eP.y*ArcBorderUtils.bez(N,2,i*STEP);
				_points[i+1] = p;
			}
			_points[_points.length-1] = new Point(endPoint.next.data.x,endPoint.next.data.y);

			/*
			 *	画墙
			 */
			
			if(surfaces.length)
			{
				surfaces[0].dispose();
				surfaces[1].dispose();
				surfaces[2].dispose();
			}
			
			/*
			网格初始化
			*/
			
			//内墙
			surfaces[0] = new Surface3D();
			var shader:Shader3D = this.material.clone() as Shader3D;
			if(shader.filters.length > 1)
				shader.filters.pop();
			surfaces[0].material = shader as Material3D;
			surfaces[0].addVertexData( Surface3D.POSITION );
			surfaces[0].addVertexData( Surface3D.UV0 );
			surfaces[0].addVertexData( Surface3D.NORMAL );
			//墙顶
			surfaces[1] = new Surface3D();
			surfaces[1].material = DefaultMaterial.getInst();
			surfaces[1].addVertexData( Surface3D.POSITION );
			surfaces[1].addVertexData( Surface3D.UV0 );
			surfaces[1].addVertexData( Surface3D.NORMAL );
			//外墙
			surfaces[2] = new Surface3D();
			surfaces[2].material = DefaultMaterial.getInst();
			surfaces[2].addVertexData( Surface3D.POSITION );
			surfaces[2].addVertexData( Surface3D.UV0 );
			surfaces[2].addVertexData( Surface3D.NORMAL );
			
			for(var j:uint = 0; j < _points.length-3; j++)
				this.drawBorder( _points[j], _points[j+1], _points[j+2],_points[j+3], j);
			
			//更新贴图大小
			//内墙
			shader = surfaces[0].material as Shader3D;
			var texFilter:TextureFilter = shader.filters[0] as TextureFilter;
			var point:Point = new Point(surfaces[0].vertexVector[0] - surfaces[0].vertexVector[16], surfaces[0].vertexVector[2] - surfaces[0].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			//墙顶
			shader = surfaces[1].material as Shader3D;
			texFilter = shader.filters[0] as TextureFilter;
			point = new Point(surfaces[1].vertexVector[0] - surfaces[1].vertexVector[16], surfaces[1].vertexVector[2] - surfaces[1].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			//外墙
			shader = surfaces[2].material as Shader3D;
			texFilter = shader.filters[0] as TextureFilter;
			point = new Point(surfaces[2].vertexVector[0] - surfaces[2].vertexVector[16], surfaces[2].vertexVector[2] - surfaces[2].vertexVector[18]);
			texFilter.repeatX = point.length/150;
			
			surfaces[0].upload(this.scene);
			surfaces[1].upload(this.scene);
			surfaces[2].upload(this.scene);
			
			this.updateBoundings();
			
			mouse.addCollisionWith(this);
		}
		
		public function get points():Vector.<Point>
		{
			return this._points;
		}
		
		public function drawBorder(pre:Point,start:Point,end:Point,next:Point,index:uint):void
		{
			/*
			计算墙体数据
			*/
			
			var insidePoint:Point;     //内墙顶点坐标
			var outsidePoint:Point;    //外墙顶点坐标
			var prevVector:Point;      //当前控制点到前一控制点向量
			var nextVector:Point;      //当前控制点到后一控制点向量
			var distance:Number;       //控制点到内外墙点顶点的距离
			var insideVector:Point;    //当前控制点向房间内部的向量

			
			//前
			prevVector = new Point( pre.x - start.x, pre.y - start.y);
			nextVector = new Point( end.x - start.x, end.y - start.y);
			
			insideVector = getInsideVector(prevVector,nextVector);
			insidePoint = new Point(start.x + insideVector.x, start.y + insideVector.y);
			outsidePoint = new Point(start.x - insideVector.x, start.y - insideVector.y);
			
			//0
			surfaces[0].vertexVector.push(insidePoint.x, 0, insidePoint.y, index%2, 0, 0, 1, 1);
			//1
			surfaces[0].vertexVector.push(insidePoint.x, RoomParameters.wallHeight, insidePoint.y, index%2, 1, 0, 1, 0);
			//1
			surfaces[1].vertexVector.push(insidePoint.x, RoomParameters.wallHeight, insidePoint.y, index%2, 0, 0, 1, 0);
			//2
			surfaces[1].vertexVector.push(outsidePoint.x, RoomParameters.wallHeight, outsidePoint.y, index%2, 1, 0, 1, 0);
			//2
			surfaces[2].vertexVector.push(outsidePoint.x, RoomParameters.wallHeight, outsidePoint.y, index%2, 1, 0, 1, 0);
			//3
			surfaces[2].vertexVector.push(outsidePoint.x, 0, outsidePoint.y, index%2, 0, 0, 1, 1);
			
			if(index == _points.length - 4)
			{
				//后
				prevVector = new Point( start.x - end.x, start.y - end.y);
				nextVector = new Point( next.x - end.x, next.y - end.y);
				insideVector = getInsideVector(prevVector,nextVector);
				insidePoint = new Point(end.x + insideVector.x, end.y + insideVector.y);
				outsidePoint = new Point(end.x - insideVector.x, end.y - insideVector.y);
				
				//4
				surfaces[0].vertexVector.push(insidePoint.x, 0, insidePoint.y, index%2+1, 0, 0, 1, 1);
				//5
				surfaces[0].vertexVector.push(insidePoint.x, RoomParameters.wallHeight, insidePoint.y, index%2+1, 1, 0, 1, 0);
				//5
				surfaces[1].vertexVector.push(insidePoint.x, RoomParameters.wallHeight, insidePoint.y, index%2+1, 0, 0, 1, 0);
				//6
				surfaces[1].vertexVector.push(outsidePoint.x, RoomParameters.wallHeight, outsidePoint.y, index%2+1, 1, 0, 1, 0);
				//6
				surfaces[2].vertexVector.push(outsidePoint.x, RoomParameters.wallHeight, outsidePoint.y, index%2+1, 1, 0, 1, 0);
				//7
				surfaces[2].vertexVector.push(outsidePoint.x, 0, outsidePoint.y, index%2+1, 0, 0, 1, 1);
			}
			
			if(index)
			{
				//内墙，墙顶，外墙；
				surfaces[0].indexVector.push(0+2*(index-1),1+2*(index-1),2+2*(index-1),2+2*(index-1),1+2*(index-1),3+2*(index-1));
				surfaces[1].indexVector.push(0+2*(index-1),1+2*(index-1),2+2*(index-1),2+2*(index-1),1+2*(index-1),3+2*(index-1));
				surfaces[2].indexVector.push(0+2*(index-1),1+2*(index-1),2+2*(index-1),2+2*(index-1),1+2*(index-1),3+2*(index-1));
				if(index == _points.length - 4)
				{
					surfaces[0].indexVector.push(0+2*index,1+2*index,2+2*index,2+2*index,1+2*index,3+2*index);
					surfaces[1].indexVector.push(0+2*index,1+2*index,2+2*index,2+2*index,1+2*index,3+2*index);
					surfaces[2].indexVector.push(0+2*index,1+2*index,2+2*index,2+2*index,1+2*index,3+2*index);
				}
			}
		}
		
		private function isClockwise(x0:Number, y0:Number, x1:Number, y1:Number, x2:Number, y2:Number):Boolean
		{
			if (x0 * y1 + x1 * y2 + x2 * y0 - x1 * y0 - x2 * y1 - x0 * y2 <= 0)
				return true;
			else
				return false;
		}
		
		private function getInsideVector(prevVector:Point, nextVector:Point):Point
		{
			var angle:Number = Math.acos(getCos(prevVector,nextVector));
			var distance:Number = RoomParameters.wallWidth/Math.sin(angle/2);
			var prevAngle:Number = Math.atan(prevVector.y/prevVector.x);
			if (prevVector.x<0)
			{
				prevAngle = prevAngle - Math.PI;
			}	
			var nextAngle:Number = Math.atan(nextVector.y/nextVector.x);
			if (nextVector.x<0)
			{
				nextAngle = nextAngle - Math.PI;
			}
			var middleAngle	:Number = (nextAngle + prevAngle) /2
			
			var insideVector:Point = new Point(Math.cos(middleAngle) * distance, Math.sin(middleAngle) * distance);
			if (isClockwise(-prevVector.x, -prevVector.y, 0, 0, insideVector.x,insideVector.y))
			{
				insideVector.x = -insideVector.x;
				insideVector.y = -insideVector.y;
			}
			return insideVector;
		}
		
		//求vec1和vec2夹角的余弦值
		private function getCos( vec1:Point, vec2:Point ):Number
		{
			if(vec1.length == 0 || vec2.length == 0)
				return 0;
			return ( ( vec1.x*vec2.x + vec1.y*vec2.y ) / (vec1.length*vec2.length) );
		}
	}
}